/**
 * @file Modbus_master.c
 * @author Linquan
 * @brief 
 * @version 1.0
 * @date 2025-09-19
 * 
 * @copyright Copyright (c) 2025
 * @ brief
 *   基于RTX5的modbus主站框架
 *	 支持 超时重发送（可设置超时时间与重发送次数），
 *	 提供 接收报文CRC校验功能， 可根据发送请求自定义配置报文解析函数。
 * @history
 *   2025-9-19:
 *   支持 01 03 06 10功能码请求
 *
 *
 *
 */


 #if USE_RTX


#include "Modbus_master.h"
#include <string.h>



// CRC16计算函数
static uint16_t Modbus_CRC16(uint8_t *data, uint16_t len) 
{
    uint16_t crc = 0xFFFF;
    for (uint16_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}


/* 获得从机地址以及 功能码，检查 异常功能码 

	return 1 = fail 0 = success
*/
uint8_t ModbusMaster_addr_code_check(uint8_t *raw_data, uint8_t *slave_addr, uint8_t *function_code)
{
	// 3. 提取基础信息
    *slave_addr = raw_data[0];
    *function_code = raw_data[1];
    
    // 4. 检查异常响应（功能码最高位为1）
    if (raw_data[1] & 0x80) 
	{       
        return 1;
    }

	return 0;
}



/* 检查CRC 
   返回值 0 = fail, 1 = success
*/
uint8_t ModbusMaster_CRC_check(uint8_t *raw_data, uint16_t data_len)
{
	uint16_t received_crc = (raw_data[data_len - 1] << 8) | raw_data[data_len - 2];
    uint16_t calculated_crc = Modbus_CRC16(raw_data, data_len - 2);
	
    if (received_crc != calculated_crc) {
        return 0;
    }
	return 1;
}




// 初始化Modbus主站
uint8_t ModbusMaster_Init(ModbusMaster_t *master, void (*Master_send)(uint8_t* tx_buffer, uint16_t tx_len)) 
{
    memset(master, 0, sizeof(ModbusMaster_t));
    
	// 创建总线锁(互斥锁)
    master->bus_lock = MUTE_BUS_UNLOCK;
	
	// 设置发送函数
	master->Master_send = Master_send;
	
    // 创建请求队列
    master->req_queue = osMessageQueueNew(16, sizeof(ModbusRequest_t), NULL);
    if (master->req_queue == NULL) return 1;
    
   
    
    // 创建响应超时定时器
    master->timeout_timer = osTimerNew(Modbus_ResponseTimeout_Callback, osTimerOnce, master, NULL);
    if (master->timeout_timer == NULL) return 3;
	
   
	
    return 0;
}

// 读取线圈状态
uint8_t ModbusMaster_ReadCoils(ModbusMaster_t *master, uint8_t slave_addr, 
                             uint16_t start_addr, uint16_t count, 
                             uint32_t timeout, void (*callback)(void *)) 
{
    ModbusRequest_t req;
    memset(&req, 0, sizeof(ModbusRequest_t));
    
    req.slave_addr = slave_addr;
    req.function_code = MODBUS_FC_READ_COILS;
    req.start_addr = start_addr;
    req.data_len = count;
    req.timeout = timeout;
    req.callback = callback;
    req.retry_count = 0;  // 初始化重传计数器
    
    // 发送请求到队列
    return osMessageQueuePut(master->req_queue, &req, 0, 100);
}

// 读取保持寄存器
uint8_t ModbusMaster_ReadHoldingRegisters(ModbusMaster_t *master, uint8_t slave_addr, 
                                        uint16_t start_addr, uint16_t count, 
                                        uint32_t timeout, void (*callback)(void *)) 
{
    ModbusRequest_t req;
    memset(&req, 0, sizeof(ModbusRequest_t));
    
    req.slave_addr = slave_addr;
    req.function_code = MODBUS_FC_READ_HOLDING;
    req.start_addr = start_addr;
    req.data_len = count;
    req.timeout = timeout;
    req.callback = callback;
    req.retry_count = 0;  // 初始化重传计数器
    
    // 发送请求到队列
    return osMessageQueuePut(master->req_queue, &req, 0, 100);
}


// 写单个保持寄存器
uint8_t ModbusMaster_WriteSingleRegister(ModbusMaster_t *master, uint8_t slave_addr, 
                                       uint16_t reg_addr, uint16_t value, 
                                       uint32_t timeout, void (*callback)(void *)) 
{
    ModbusRequest_t req;
    memset(&req, 0, sizeof(ModbusRequest_t));
    
    req.slave_addr = slave_addr;
    req.function_code = MODBUS_FC_WRITE_SINGLE;
    req.start_addr = reg_addr;
    req.data_len = 1;  // 单个寄存器
    req.timeout = timeout;
    req.callback = callback;
    req.retry_count = 0;
    
    // 存储要写入的值
    static uint16_t write_value;  // 静态变量用于传递数据
    write_value = value;
    req.data = (uint8_t*)&write_value;
    
    return osMessageQueuePut(master->req_queue, &req, 0, 100);
}

// 写多个保持寄存器
uint8_t ModbusMaster_WriteMultipleRegisters(ModbusMaster_t *master, uint8_t slave_addr, 
                                          uint16_t start_addr, uint16_t count, 
                                          uint16_t *values, uint32_t timeout, 
                                          void (*callback)(void *)) 
{
    ModbusRequest_t req;
    memset(&req, 0, sizeof(ModbusRequest_t));
    
    req.slave_addr = slave_addr;
    req.function_code = MODBUS_FC_WRITE_MULTIPLE;
    req.start_addr = start_addr;
    req.data_len = count;  // 寄存器数量
    req.timeout = timeout;
    req.callback = callback;
    req.retry_count = 0;
    req.data = (uint8_t*)values;  // 转换为字节指针
    
    return osMessageQueuePut(master->req_queue, &req, 0, 100);
}


 
/*  Modbus发送任务 */ 
void Task_Modbus_SendAndRecv(void *argument) 
{
   ModbusMaster_t *master = (ModbusMaster_t*)argument;
   uint8_t tx_buffer[MODBUS_MAX_DATA_LEN + 4]; // 数据+CRC
   uint16_t tx_len;
    
	
    while (1) 
    {		
        // 等待请求队列中的请求
        if (osMessageQueueGet(master->req_queue, &master->current_req, NULL, osWaitForever) == osOK) 
        {			
			uint8_t need_resend = 0;
	
			do {
				master->bus_lock = MUTE_BUS_LOCK;
				need_resend = 0;
				master->current_req.status = MODBUS_STATUS_SENDING;
				tx_len = 0;
				
				// 填充从站地址和功能码
				tx_buffer[tx_len++] = master->current_req.slave_addr;
				tx_buffer[tx_len++] = master->current_req.function_code;
				
				// 根据功能码填充数据
				switch (master->current_req.function_code) 
				{
					case MODBUS_FC_READ_COILS:
					case MODBUS_FC_READ_DISCRETE:
					case MODBUS_FC_READ_HOLDING:
					case MODBUS_FC_READ_INPUT:
						// 读操作：起始地址(2字节) + 数量(2字节)
						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
						tx_buffer[tx_len++] = (master->current_req.data_len >> 8) & 0xFF;
						tx_buffer[tx_len++] = master->current_req.data_len & 0xFF;
						break;
						
					case MODBUS_FC_WRITE_SINGLE:
						// 写单个寄存器：地址(2字节) + 数据(2字节)
						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
					
						if (master->current_req.data) 
						{
							uint16_t value = *(uint16_t*)master->current_req.data;
							tx_buffer[tx_len++] = (value >> 8) & 0xFF;
							tx_buffer[tx_len++] = value & 0xFF;
						}
						break;
						
					case MODBUS_FC_WRITE_MULTIPLE:
						// 写多个寄存器：起始地址(2字节) + 数量(2字节) + 字节数(1字节) + 数据(n*2字节)
						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
						tx_buffer[tx_len++] = (master->current_req.data_len >> 8) & 0xFF;
						tx_buffer[tx_len++] = master->current_req.data_len & 0xFF;
						
						tx_buffer[tx_len++] = master->current_req.data_len * 2; // 字节数
						
						// 填充数据(每个寄存器2字节)
						if (master->current_req.data) 
						{
							uint16_t *values = (uint16_t*)master->current_req.data;
							for (uint16_t i = 0; i < master->current_req.data_len; i++) {
								tx_buffer[tx_len++] = (values[i] >> 8) & 0xFF;
								tx_buffer[tx_len++] = values[i] & 0xFF;
							}
						}
						break;
				}
				
				// 计算并添加CRC
				uint16_t crc = Modbus_CRC16(tx_buffer, tx_len);
				tx_buffer[tx_len++] = crc & 0xFF;
				tx_buffer[tx_len++] = (crc >> 8) & 0xFF;
				
				// 发送数据                                  
				master->Master_send(tx_buffer, tx_len);
				
				// 启动超时定时器
				osTimerStop(master->timeout_timer);
				osTimerStart(master->timeout_timer, master->current_req.timeout);
				
				// 等待响应或超时
				master->current_req.status = MODBUS_STATUS_WAITING;
				master->rx_index = 0;
				memset(master->rx_buffer, 0, sizeof(master->rx_buffer));
									
				
			   /* 等待接收完成，或响应超时 */
				while(master->bus_lock == MUTE_BUS_LOCK)
				{
					osThreadYield();
				}				
				
				// 检查是否需要重传
#if MODBUS_ENABLE_RETRY
				if (master->current_req.status == MODBUS_STATUS_TIMEOUT && 
					master->current_req.retry_count < MODBUS_MAX_RETRY_COUNT) 
				{
					master->current_req.retry_count++;
					need_resend = 1;
				}
#endif
				
			} while (need_resend);
			
			// 进行CRC校验
			if(ModbusMaster_CRC_check(master->rx_buffer, master->rx_index))
			{
				// 执行回调函数通知结果
				if (master->current_req.callback != NULL) 
				{
					master->current_req.callback(master);// 传入主站节点 处理接收缓冲区数据
				}	
			}			          
        }
    }
}


//// 初始化协程状态变量（静态uint32_t，保存执行位置标记）
//#define CO_INIT(s)  static uint32_t s = 0;

//// 启动/恢复协程执行（从上次保存的状态继续，对应switch入口）
//#define CO_START(s) switch(s) { case 0:

//// 保存当前执行状态（记录行号作为标记，下次从这里恢复）
//#define CO_YIELD(s) s = __LINE__; case __LINE__:

//// 结束协程状态块（重置状态并闭合switch结构）
//#define CO_END(s)   s = 0; }

//// 等待直到条件满足（不满足则保存状态并退出，下次恢复再判断）
//#define CO_WAIT_UNTIL(co, condition)        \
//  do {                                       \
//    CO_YIELD(co);                            \
//    if (!(condition)) {                      \
//      return;                                \
//    }                                         \
//  } while(0)

//// 等待条件为真时暂停（条件为真则保存状态退出，直到条件为假再继续）
//#define CO_WAIT_WHILE(co, cond)  CO_WAIT_UNTIL((co), !(cond))

//// 重启协程（重置状态为初始值，下次执行从开头重新开始）
//#define CO_RESTART(s)  do { (s) = 0; return; } while(0)


////excample：把函数放到裸机的主循环里即可实现伪线程
//void pt_test()
//{
//	CO_INIT(wait_reply);
//	CO_START(wait_reply);
//		
//	// 等待队列存在事件
//	
//	//发送数据
//	
//	//等待回复或超时
//	CO_WAIT_UNTIL(wait_reply, (reply_is_recved()))
//	
//	// 解析数据
//		
//		
//	CO_END(wait_reply);

//}



//void SSSSSSSSSSTask_Modbus_SendAndRecv(void *argument) 
//{
//   ModbusMaster_t *master = (ModbusMaster_t*)argument;
//   uint8_t tx_buffer[MODBUS_MAX_DATA_LEN + 4]; // 数据+CRC
//   uint16_t tx_len;
//    
//	
//CO_INIT(wait_reply_flag);
//CO_START(wait_reply_flag);	
		
//        // 等待请求队列中的请求
//        if (osMessageQueueGet(master->req_queue, &master->current_req, NULL, osWaitForever) == osOK) 
//        {			
//			uint8_t need_resend = 0;
//	
//			do {
//				master->bus_lock = MUTE_BUS_LOCK;
//				need_resend = 0;
//				master->current_req.status = MODBUS_STATUS_SENDING;
//				tx_len = 0;
//				
//				// 填充从站地址和功能码
//				tx_buffer[tx_len++] = master->current_req.slave_addr;
//				tx_buffer[tx_len++] = master->current_req.function_code;
//				
//				// 根据功能码填充数据
//				switch (master->current_req.function_code) 
//				{
//					case MODBUS_FC_READ_COILS:
//					case MODBUS_FC_READ_DISCRETE:
//					case MODBUS_FC_READ_HOLDING:
//					case MODBUS_FC_READ_INPUT:
//						// 读操作：起始地址(2字节) + 数量(2字节)
//						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
//						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
//						tx_buffer[tx_len++] = (master->current_req.data_len >> 8) & 0xFF;
//						tx_buffer[tx_len++] = master->current_req.data_len & 0xFF;
//						break;
//						
//					case MODBUS_FC_WRITE_SINGLE:
//						// 写单个寄存器：地址(2字节) + 数据(2字节)
//						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
//						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
//					
//						if (master->current_req.data) 
//						{
//							uint16_t value = *(uint16_t*)master->current_req.data;
//							tx_buffer[tx_len++] = (value >> 8) & 0xFF;
//							tx_buffer[tx_len++] = value & 0xFF;
//						}
//						break;
//						
//					case MODBUS_FC_WRITE_MULTIPLE:
//						// 写多个寄存器：起始地址(2字节) + 数量(2字节) + 字节数(1字节) + 数据(n*2字节)
//						tx_buffer[tx_len++] = (master->current_req.start_addr >> 8) & 0xFF;
//						tx_buffer[tx_len++] = master->current_req.start_addr & 0xFF;
//						tx_buffer[tx_len++] = (master->current_req.data_len >> 8) & 0xFF;
//						tx_buffer[tx_len++] = master->current_req.data_len & 0xFF;
//						
//						tx_buffer[tx_len++] = master->current_req.data_len * 2; // 字节数
//						
//						// 填充数据(每个寄存器2字节)
//						if (master->current_req.data) 
//						{
//							uint16_t *values = (uint16_t*)master->current_req.data;
//							for (uint16_t i = 0; i < master->current_req.data_len; i++) {
//								tx_buffer[tx_len++] = (values[i] >> 8) & 0xFF;
//								tx_buffer[tx_len++] = values[i] & 0xFF;
//							}
//						}
//						break;
//				}
//				
//				// 计算并添加CRC
//				uint16_t crc = Modbus_CRC16(tx_buffer, tx_len);
//				tx_buffer[tx_len++] = crc & 0xFF;
//				tx_buffer[tx_len++] = (crc >> 8) & 0xFF;
//				
//				// 发送数据                                  
//				master->Master_send(tx_buffer, tx_len);
//				
//				// 启动超时定时器
//				osTimerStop(master->timeout_timer);
//				osTimerStart(master->timeout_timer, master->current_req.timeout);
//				
//				// 等待响应或超时
//				master->current_req.status = MODBUS_STATUS_WAITING;
//				master->rx_index = 0;
//				memset(master->rx_buffer, 0, sizeof(master->rx_buffer));
//									
//				
//			   /* 等待接收完成，或响应超时 */				
//CO_WAIT_WHILE(wait_reply_flag, (master->bus_lock == MUTE_BUS_LOCK));			
//				
//				// 检查是否需要重传
//#if MODBUS_ENABLE_RETRY
//				if (master->current_req.status == MODBUS_STATUS_TIMEOUT && 
//					master->current_req.retry_count < MODBUS_MAX_RETRY_COUNT) 
//				{
//					master->current_req.retry_count++;
//					need_resend = 1;
//				}
//#endif
//				
//			} while (need_resend);
//			
//			// 进行CRC校验
//			if(ModbusMaster_CRC_check(master->rx_buffer, master->rx_index))
//			{
//				// 执行回调函数通知结果
//				if (master->current_req.callback != NULL) 
//				{
//					master->current_req.callback(master);// 传入主站节点 处理接收缓冲区数据
//				}	
//			}			          
//        }

//	CO_END(wait_reply_flag);
//}


//void Task_Modbus_SendAndRecv(void *argument) 
//{
//	while(1)
//	{
//		SSSSSSSSSSTask_Modbus_SendAndRecv(argument);
//	
//		//printf("dddddd\r\n");
//	}

//}


// 软定时器的响应超时回调函数，用于重发送
void Modbus_ResponseTimeout_Callback(void *argument) 
{
    ModbusMaster_t *master = (ModbusMaster_t*)argument; 
    
    // 设置超时状态
    master->current_req.status = MODBUS_STATUS_TIMEOUT;
    
    // 释放总线锁，让发送任务处理重传
    master->bus_lock = MUTE_BUS_UNLOCK;	

}
    


// Modbus接收（通常在UART中断中处理）
void Modbus_RTU_RecvTask(ModbusMaster_t*master, uint8_t data) 
{   	
	//  在 主站发送后等待回复时，才能开始接收
	if( master->current_req.status == MODBUS_STATUS_WAITING)
	{				
		 // 继续接收下一个字节
        if (master->rx_index < sizeof(master->rx_buffer)) 
        {
			master->rx_buffer[master->rx_index++] = data;           
        }
        else 
        {
            // 接收缓冲区已满，处理完整帧
			
            master->current_req.status = MODBUS_STATUS_COMPLETE;
            osTimerStop(master->timeout_timer);
            master->bus_lock = MUTE_BUS_UNLOCK;	
        }
	}      
}


// 接收帧超时，用于确定接收完成
 void Modbus_Recv_Timeout(ModbusMaster_t*master)
{			
	master->current_req.status = MODBUS_STATUS_COMPLETE;// 接收完成
	osTimerStop(master->timeout_timer);// 重发送超时定时器停止
	master->bus_lock = MUTE_BUS_UNLOCK;	//接收完成，释放锁，在发送任务中对接收数据进行解析处理。
	printf("recv finish\r\n");
	
}



#if 0
/* 请求发送示例 */
void Excample_req_send()
{
	uint8_t addr = 1;
	ModbusMaster_ReadHoldingRegisters(&modbus_master, 1, 
									 addr, 3, 
									200, &MB_Master_handle); 
	
	ModbusMaster_WriteSingleRegister(&modbus_master, 2, 
								   addr, 0XAABB, 
								   200, &MB_Master_handle) ;
	
	uint16_t data[5] = {1,2,3,4,5};
	ModbusMaster_WriteMultipleRegisters(&modbus_master, 2, 
								   addr, sizeof(data)/sizeof(data[0]), data, 
								   200, &MB_Master_handle) ;							   
}



/* 解析函数示例 */
void Excample_ModbusMaster_data_handle(void *ptr)
{
	uint8_t slave_adddr, func_code;
	
	ModbusMaster_t *master = (ModbusMaster_t*)ptr; 
	
	/* 校验错误码 获得 地址及功能码 */
	if(ModbusMaster_addr_code_check(master->rx_buffer, &slave_adddr, &func_code)){ return;}		
	
    switch (func_code) 
	{
        case MODBUS_FC_READ_COILS:
        case MODBUS_FC_READ_DISCRETE:
          // 填入具体解析函数				
            break;
            
        case MODBUS_FC_READ_HOLDING:
        case MODBUS_FC_READ_INPUT:
            // 填入具体解析函数		
            break;
            
        case MODBUS_FC_WRITE_SINGLE:
        case MODBUS_FC_WRITE_MULTIPLE:
            // 写操作响应只需确认成功，无数据需要解析
            break;   
		
        default:
           break;
    }
}



#endif


#endif
